
#include "ObjMeta.h"
#include "Class.h"
#include "vm.h"
#include "ObjFn.h"


ObjFn *ObjFn::NewObjFn(VM *vm, ObjModule *objModule, uint32_t slotNum) {
    auto *objFn = ALLOCATE(vm, ObjFn);
    if (objFn == nullptr) {
        MEM_ERROR("allocate ObjFn failed!");
    }
    objFn->objHeader = *new ObjHeader(vm, OT_FUNCTION, vm->fnClass);
    ByteBufferInit(&objFn->instrStream);
    ValueBufferInit(&objFn->constants);
    objFn->module = objModule;
    objFn->maxStackSlotUsedNum = slotNum;
    objFn->upvalueNum = objFn->argNum = 0;
#ifdef DEBUG
    objFn->debug = ALLOCATE(vm, FnDebug);
    objFn->debug->fnName = NULL;
    IntBufferInit(&objFn->debug->lineNo);
#endif
    return objFn;
}

ObjFn::ObjFn(VM *vm, ObjModule *objModule, uint32_t slotNum) {
    auto *objFn = ALLOCATE(vm, ObjFn);
    if (objFn == nullptr) {
        MEM_ERROR("allocate ObjFn failed!");
    }
    objFn->objHeader = *new ObjHeader(vm, OT_FUNCTION, vm->fnClass);
    ByteBufferInit(&objFn->instrStream);
    ValueBufferInit(&objFn->constants);
    objFn->module = objModule;
    objFn->maxStackSlotUsedNum = slotNum;
    objFn->upvalueNum = objFn->argNum = 0;
#ifdef DEBUG
    objFn->debug = ALLOCATE(vm, FnDebug);
    objFn->debug->fnName = NULL;
    IntBufferInit(&objFn->debug->lineNo);
#endif

    this->objHeader = objFn->objHeader;
    this->instrStream = objFn->instrStream;
    this->constants = objFn->constants;
    this->module = objFn->module;
    this->maxStackSlotUsedNum = objFn->maxStackSlotUsedNum;
    this->argNum = objFn->argNum;
    this->upvalueNum = objFn->upvalueNum;

}

ObjUpvalue *ObjUpvalue::NewObjUpvalue(VM *vm, Value *localVarPtr) {
    auto *objUpvalue = ALLOCATE(vm, ObjUpvalue);
    objUpvalue->objHeader = *new ObjHeader(vm, OT_UPVALUE, nullptr);
    objUpvalue->localVarPtr = localVarPtr;
    objUpvalue->closedUpvalue = VT_TO_VALUE(VT_NULL);
    objUpvalue->next = nullptr;
    return objUpvalue;
}

ObjUpvalue::ObjUpvalue(VM *vm, Value *localVarPtr) {
    auto *objUpvalue = ALLOCATE(vm, ObjUpvalue);
    objUpvalue->objHeader = *new ObjHeader(vm, OT_UPVALUE, nullptr);
    objUpvalue->localVarPtr = localVarPtr;
    objUpvalue->closedUpvalue = VT_TO_VALUE(VT_NULL);
    objUpvalue->next = nullptr;

    this->objHeader = objUpvalue->objHeader;
    this->closedUpvalue = objUpvalue->closedUpvalue;
    this->localVarPtr = objUpvalue->localVarPtr;
    this->next = objUpvalue->next;

}

ObjClosure *ObjClosure::NewObjClosure(VM *vm, ObjFn *objFn) {
    auto *objClosure = ALLOCATE_EXTRA(vm, ObjClosure, sizeof(ObjUpvalue *) * objFn->upvalueNum);
    objClosure->objHeader = *new ObjHeader(vm, OT_CLOSURE, vm->fnClass);
    objClosure->fn = objFn;
    //清除upvalue数组做 以避免在填充upvalue数组之前触发GC
    uint32_t idx = 0;
    while (idx < objFn->upvalueNum) {
        objClosure->upvalues[idx] = nullptr;
        idx++;
    }

    return objClosure;
}

ObjClosure::ObjClosure(VM *vm, ObjFn *objFn) {
    auto *objClosure = ALLOCATE_EXTRA(vm, ObjClosure, sizeof(ObjUpvalue *) * objFn->upvalueNum);
    objClosure->objHeader = *new ObjHeader(vm, OT_CLOSURE, vm->fnClass);
    objClosure->fn = objFn;
    //清除upvalue数组做 以避免在填充upvalue数组之前触发GC
    uint32_t idx = 0;
    while (idx < objFn->upvalueNum) {
        this->upvalues[idx] = nullptr;
        idx++;
    }

    this->objHeader = objClosure->objHeader;
    this->fn = objClosure->fn;

}
